#!/bin/bash
###############################################################################
#       脚本名称: test_utils_jq.sh
#       功能描述: JSON数据处理工具(utils_jq.sh)单元测试
#       作者: 林再来
#       日期: 2025-10-15
#       版本: 1.0
#       功能:
#           1、测试工具层JSON数据处理的所有核心功能
#           2、验证数据读写、数组对象操作、查询过滤等功能
#           3、确保工具层的独立性和纯粹性
###############################################################################

# 切换到脚本目录
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1

# 加载测试框架
source ../test_framework.sh

# 加载被测模块
source ../../../scripts/utils/utils_jq.sh

# 创建临时测试目录
TEST_DIR=$(create_test_dir)

###############################################################################
# 测试用例
###############################################################################

# 测试: jq工具初始化
test_utils_jq_init() {
    utils_jq_init 2>/dev/null
    assert_not_empty "$utils_jq_binary" "jq工具应该被初始化"
}

# 测试: JSON文件验证 - 有效文件
test_utils_jq_validate_valid() {
    local test_file="$TEST_DIR/valid.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "TestApp",
    "version": "1.0.0"
  },
  "database": {
    "host": "localhost",
    "port": 3306
  }
}
EOF
    
    utils_jq_validate "$test_file" 2>/dev/null
}

# 测试: JSON文件验证 - 无效文件
test_utils_jq_validate_invalid() {
    local test_file="$TEST_DIR/invalid.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "TestApp"
    invalid syntax
  }
}
EOF
    
    ! utils_jq_validate "$test_file" 2>/dev/null
}

# 测试: 读取JSON值 - 字符串
test_utils_jq_read_string() {
    local test_file="$TEST_DIR/read_string.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "MyApp",
    "description": "This is a test application"
  }
}
EOF
    
    local name=$(utils_jq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name"
    
    local desc=$(utils_jq_read "$test_file" ".app.description" 2>/dev/null)
    assert_equals "This is a test application" "$desc"
}

# 测试: 读取JSON值 - 数字和布尔值
test_utils_jq_read_types() {
    local test_file="$TEST_DIR/read_types.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "port": 8080,
    "timeout": 30.5,
    "debug": true,
    "enabled": false
  }
}
EOF
    
    local port=$(utils_jq_read "$test_file" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
    
    local timeout=$(utils_jq_read "$test_file" ".app.timeout" 2>/dev/null)
    assert_equals "30.5" "$timeout"
    
    local debug=$(utils_jq_read "$test_file" ".app.debug" 2>/dev/null)
    assert_equals "true" "$debug"
}

# 测试: 读取嵌套JSON值
test_utils_jq_read_nested() {
    local test_file="$TEST_DIR/read_nested.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "database": {
      "mysql": {
        "host": "localhost",
        "port": 3306,
        "credentials": {
          "username": "root",
          "password": "secret"
        }
      }
    }
  }
}
EOF
    
    local host=$(utils_jq_read "$test_file" ".app.database.mysql.host" 2>/dev/null)
    assert_equals "localhost" "$host"
    
    local username=$(utils_jq_read "$test_file" ".app.database.mysql.credentials.username" 2>/dev/null)
    assert_equals "root" "$username"
}

# 测试: 写入JSON值 - 字符串
test_utils_jq_write_string() {
    local test_file="$TEST_DIR/write_string.json"
    echo "{}" > "$test_file"
    
    utils_jq_write "$test_file" ".app.name" "TestApp" "string" 2>/dev/null
    utils_jq_write "$test_file" ".app.env" "production" "string" 2>/dev/null
    
    local name=$(utils_jq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "TestApp" "$name"
    
    local env=$(utils_jq_read "$test_file" ".app.env" 2>/dev/null)
    assert_equals "production" "$env"
}

# 测试: 写入JSON值 - 数字和布尔值
test_utils_jq_write_types() {
    local test_file="$TEST_DIR/write_types.json"
    echo "{}" > "$test_file"
    
    utils_jq_write "$test_file" ".app.port" "8080" "number" 2>/dev/null
    utils_jq_write "$test_file" ".app.debug" "true" "boolean" 2>/dev/null
    utils_jq_write "$test_file" ".app.enabled" "false" "boolean" 2>/dev/null
    
    local port=$(utils_jq_read "$test_file" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
    
    local debug=$(utils_jq_read "$test_file" ".app.debug" 2>/dev/null)
    assert_equals "true" "$debug"
}

# 测试: 删除JSON键
test_utils_jq_delete() {
    local test_file="$TEST_DIR/delete_test.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "temp": "should_be_deleted",
    "debug": true
  }
}
EOF
    
    utils_jq_delete "$test_file" ".app.temp" 2>/dev/null
    
    local temp=$(utils_jq_read "$test_file" ".app.temp" 2>/dev/null)
    assert_empty "$temp" "删除的键应该不存在"
    
    local name=$(utils_jq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name" "其他键应该保持不变"
}

# 测试: 合并JSON文件
test_utils_jq_merge() {
    local target="$TEST_DIR/target_merge.json"
    local source="$TEST_DIR/source_merge.json"
    
    cat > "$target" << 'EOF'
{
  "app": {
    "name": "TargetApp",
    "version": "1.0.0"
  }
}
EOF
    
    cat > "$source" << 'EOF'
{
  "app": {
    "name": "SourceApp",
    "port": 8080
  }
}
EOF
    
    utils_jq_merge "$target" "$source" "merge" 2>/dev/null
    
    local name=$(utils_jq_read "$target" ".app.name" 2>/dev/null)
    assert_equals "SourceApp" "$name" "merge模式source应该覆盖target"
    
    local port=$(utils_jq_read "$target" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port" "source的新键应该被添加"
}

# 测试: 列出JSON键
test_utils_jq_list_keys() {
    local test_file="$TEST_DIR/list_keys.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "port": 8080,
    "debug": true
  }
}
EOF
    
    local keys=$(utils_jq_list_keys "$test_file" ".app" 2>/dev/null)
    
    assert_success grep -q "name" <<< "$keys"
    assert_success grep -q "version" <<< "$keys"
    assert_success grep -q "port" <<< "$keys"
}

# 测试: 格式化JSON文件
test_utils_jq_format() {
    local test_file="$TEST_DIR/format_test.json"
    echo '{"app":{"name":"MyApp","version":"1.0.0"}}' > "$test_file"
    
    utils_jq_format "$test_file" 2 2>/dev/null
    
    # 验证格式化后文件仍然有效
    utils_jq_validate "$test_file" 2>/dev/null
    assert_success "格式化后的文件应该有效"
    
    local name=$(utils_jq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name" "格式化不应改变数据"
}

# 测试: 数组追加元素
test_utils_jq_array_append() {
    local test_file="$TEST_DIR/array_append.json"
    cat > "$test_file" << 'EOF'
{
  "servers": ["server1", "server2"]
}
EOF
    
    utils_jq_array_append "$test_file" ".servers" "server3" 2>/dev/null
    
    local result=$(utils_jq_read "$test_file" ".servers" 2>/dev/null)
    assert_success grep -q "server3" <<< "$result"
}

# 测试: 数组删除元素 - 按索引
test_utils_jq_array_remove_index() {
    local test_file="$TEST_DIR/array_remove_index.json"
    cat > "$test_file" << 'EOF'
{
  "servers": ["server1", "server2", "server3"]
}
EOF
    
    utils_jq_array_remove "$test_file" ".servers" "1" 2>/dev/null
    
    local result=$(utils_jq_read "$test_file" ".servers" 2>/dev/null)
    assert_success grep -q "server1" <<< "$result"
    
    # server2应该被删除
    if grep -q "server2" <<< "$result"; then
        echo "server2应该被删除" >&2
        return 1
    fi
    
    assert_success grep -q "server3" <<< "$result"
}

# 测试: 数组删除元素 - 按值
test_utils_jq_array_remove_value() {
    local test_file="$TEST_DIR/array_remove_value.json"
    cat > "$test_file" << 'EOF'
{
  "servers": ["server1", "server2", "server3"]
}
EOF
    
    utils_jq_array_remove "$test_file" ".servers" "server2" 2>/dev/null
    
    local result=$(utils_jq_read "$test_file" ".servers" 2>/dev/null)
    # server2应该被删除
    if grep -q "server2" <<< "$result"; then
        echo "server2应该被删除" >&2
        return 1
    fi
}

# 测试: 对象合并
test_utils_jq_object_merge() {
    local test_file="$TEST_DIR/object_merge.json"
    cat > "$test_file" << 'EOF'
{
  "database": {
    "host": "localhost"
  }
}
EOF
    
    utils_jq_object_merge "$test_file" ".database" '{"port":3306,"user":"root"}' 2>/dev/null
    
    local host=$(utils_jq_read "$test_file" ".database.host" 2>/dev/null)
    assert_equals "localhost" "$host" "原有字段应该保留"
    
    local port=$(utils_jq_read "$test_file" ".database.port" 2>/dev/null)
    assert_equals "3306" "$port" "新字段应该被添加"
    
    local user=$(utils_jq_read "$test_file" ".database.user" 2>/dev/null)
    assert_equals "root" "$user" "新字段应该被添加"
}

# 测试: jq查询功能
test_utils_jq_query() {
    local test_file="$TEST_DIR/query_test.json"
    cat > "$test_file" << 'EOF'
{
  "servers": [
    {"name": "server1", "ip": "192.168.1.1", "active": true},
    {"name": "server2", "ip": "192.168.1.2", "active": false},
    {"name": "server3", "ip": "192.168.1.3", "active": true}
  ]
}
EOF
    
    # 查询active的服务器
    local result=$(utils_jq_query "$test_file" '.servers[] | select(.active == true) | .name' 2>/dev/null)
    
    echo "$result" | grep -q "server1"
    assert_success "应该包含server1"
    
    echo "$result" | grep -q "server3"
    assert_success "应该包含server3"
    
    echo "$result" | grep -q "server2"
    ! assert_success "不应该包含server2"
}

# 测试: jq过滤功能
test_utils_jq_filter() {
    local test_file="$TEST_DIR/filter_test.json"
    cat > "$test_file" << 'EOF'
{
  "users": [
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 17},
    {"name": "Charlie", "age": 30}
  ]
}
EOF
    
    # 过滤年龄大于18的用户
    local result=$(utils_jq_filter "$test_file" '.users | map(select(.age > 18))' 2>/dev/null)
    
    echo "$result" | grep -q "Alice"
    assert_success "应该包含Alice"
    
    echo "$result" | grep -q "Charlie"
    assert_success "应该包含Charlie"
    
    echo "$result" | grep -q "Bob"
    ! assert_success "不应该包含Bob"
}

# 测试: 备份和恢复机制
test_utils_jq_backup_restore() {
    local test_file="$TEST_DIR/backup_test.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "OriginalApp"
  }
}
EOF
    
    # 写入会创建备份
    utils_jq_write "$test_file" ".app.name" "NewApp" "string" 2>/dev/null
    
    # 验证备份被删除（成功写入后）
    local backup_count=$(ls -1 "$TEST_DIR"/backup_test.json.bak.* 2>/dev/null | wc -l)
    assert_equals "0" "$backup_count" "成功写入后备份应该被删除"
    
    local name=$(utils_jq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "NewApp" "$name"
}

# 测试: null值处理
test_utils_jq_null_handling() {
    local test_file="$TEST_DIR/null_test.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "name": "MyApp",
    "description": null
  }
}
EOF
    
    local desc=$(utils_jq_read "$test_file" ".app.description" 2>/dev/null)
    assert_empty "$desc" "null值应该返回空字符串"
    
    local nonexist=$(utils_jq_read "$test_file" ".app.nonexistent" 2>/dev/null)
    assert_empty "$nonexist" "不存在的键应该返回空字符串"
}

# 测试: 复杂嵌套结构
test_utils_jq_complex_structure() {
    local test_file="$TEST_DIR/complex.json"
    cat > "$test_file" << 'EOF'
{
  "app": {
    "services": {
      "web": {
        "servers": [
          {"host": "web1", "port": 8080},
          {"host": "web2", "port": 8080}
        ]
      },
      "database": {
        "servers": [
          {"host": "db1", "port": 3306},
          {"host": "db2", "port": 3306}
        ]
      }
    }
  }
}
EOF
    
    local web_host=$(utils_jq_read "$test_file" ".app.services.web.servers[0].host" 2>/dev/null)
    assert_equals "web1" "$web_host"
    
    local db_port=$(utils_jq_read "$test_file" ".app.services.database.servers[1].port" 2>/dev/null)
    assert_equals "3306" "$db_port"
}

###############################################################################
# 运行所有测试
###############################################################################

test_suite_start "工具层 - JSON数据处理工具 (utils_jq.sh)"

run_test "jq工具初始化" test_utils_jq_init
run_test "JSON文件验证 - 有效文件" test_utils_jq_validate_valid
run_test "JSON文件验证 - 无效文件" test_utils_jq_validate_invalid
run_test "读取JSON值 - 字符串" test_utils_jq_read_string
run_test "读取JSON值 - 数字和布尔值" test_utils_jq_read_types
run_test "读取嵌套JSON值" test_utils_jq_read_nested
run_test "写入JSON值 - 字符串" test_utils_jq_write_string
run_test "写入JSON值 - 数字和布尔值" test_utils_jq_write_types
run_test "删除JSON键" test_utils_jq_delete
run_test "合并JSON文件" test_utils_jq_merge
run_test "列出JSON键" test_utils_jq_list_keys
run_test "格式化JSON文件" test_utils_jq_format
run_test "数组追加元素" test_utils_jq_array_append
run_test "数组删除元素 - 按索引" test_utils_jq_array_remove_index
run_test "数组删除元素 - 按值" test_utils_jq_array_remove_value
run_test "对象合并" test_utils_jq_object_merge
run_test "jq查询功能" test_utils_jq_query
run_test "jq过滤功能" test_utils_jq_filter
run_test "备份和恢复机制" test_utils_jq_backup_restore
run_test "null值处理" test_utils_jq_null_handling
run_test "复杂嵌套结构" test_utils_jq_complex_structure

test_suite_end

# 清理测试目录
cleanup_test_dir "$TEST_DIR"

# 显示测试结果
print_test_summary

# 返回测试结果
exit_with_test_result

